#include "stdafx.h"
#include "dx10ConstantBuffer.h"

#include "dx10BufferUtils.h"
#include "../xrRender/dxRenderDeviceRender.h"

dx10ConstantBuffer::~dx10ConstantBuffer()
{
	DEV->_DeleteConstantBuffer(this);
//	Flush();
	_RELEASE(m_pBuffer);
	xr_free(m_pBufferData);
}

dx10ConstantBuffer::dx10ConstantBuffer(ID3D10ShaderReflectionConstantBuffer* pTable)
	: m_bChanged(true)
{
	D3D10_SHADER_BUFFER_DESC Desc;

	CHK_DX(pTable->GetDesc(&Desc));

	m_strBufferName._set(Desc.Name);
	m_eBufferType = Desc.Type;
	m_uiBufferSize = Desc.Size;

	//	Fill member list with variable descriptions
	m_MembersList.resize(Desc.Variables);
	m_MembersNames.resize(Desc.Variables);
	for (u32 i=0; i<Desc.Variables; ++i)
	{
		ID3D10ShaderReflectionVariable* pVar;
		ID3D10ShaderReflectionType*		pType;

		D3D10_SHADER_VARIABLE_DESC		var_desc;

		pVar = pTable->GetVariableByIndex(i);
		VERIFY(pVar);
		pType = pVar->GetType();
		VERIFY(pType);
		pType->GetDesc(&m_MembersList[i]);
		//	Buffers with the same layout can contain totally different members
		CHK_DX(pVar->GetDesc(&var_desc));
		m_MembersNames[i] = var_desc.Name;
	}

	m_uiMembersCRC = crc32( &m_MembersList[0], Desc.Variables*sizeof(m_MembersList[0]));

	R_CHK(dx10BufferUtils::CreateConstantBuffer(&m_pBuffer, Desc.Size));
	VERIFY(m_pBuffer);
	m_pBufferData = xr_malloc(Desc.Size);
	VERIFY(m_pBufferData);
}

bool dx10ConstantBuffer::Similar(dx10ConstantBuffer &_in)
{
	if ( m_strBufferName._get() != _in.m_strBufferName._get() )
		return false;

	if ( m_eBufferType != _in.m_eBufferType )
		return false;

	if ( m_uiMembersCRC != _in.m_uiMembersCRC )
		return false;

	if ( m_MembersList.size() != _in.m_MembersList.size() )
		return false;

	if ( memcmp(&m_MembersList[0], &_in.m_MembersList[0], m_MembersList.size()*sizeof(m_MembersList[0])) )
		return false;

	VERIFY(m_MembersNames.size() == _in.m_MembersNames.size());

	int iMemberNum = m_MembersNames.size();
	for ( int i=0; i<iMemberNum; ++i)
	{
		if (m_MembersNames[i].c_str()!=_in.m_MembersNames[i].c_str())
			return false;
	}

	return true;
}

void dx10ConstantBuffer::Flush()
{
	if (m_bChanged)
	{
		void	*pData;
		CHK_DX(m_pBuffer->Map(D3D10_MAP_WRITE_DISCARD, 0, &pData));
		VERIFY(pData);
		VERIFY(m_pBufferData);
		CopyMemory(pData, m_pBufferData, m_uiBufferSize);
		m_pBuffer->Unmap();
		m_bChanged = false;
	}
}